package com.gitee.huanminabc.fastboot.context;

import com.gitee.huanminabc.jcommon.container.ArrayUtil;
import com.gitee.huanminabc.jcommon.reflect.*;
import com.gitee.huanminabc.jcommon.str.StringUtil;
import com.gitee.huanminabc.fastboot.annotation.container.AssignBean;
import com.gitee.huanminabc.fastboot.common.Order;
import com.gitee.huanminabc.fastboot.exception.BeanContainerException;
import com.gitee.huanminabc.fastboot.load.hook.LifecycleHook;
import com.gitee.huanminabc.fastboot.load.hook.*;
import com.gitee.huanminabc.fastboot.proxy.ByteBuddyProxy;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简要描述
 *
 * @Author: huanmin
 * @Date: 2025/4/1 00:50
 * @Version: 1.0
 * @Description: 文件作用详细描述....
 */
@Slf4j
public class AppContextUtil {

    //根据class获取Bean的名称, 兼容容器注解的value
    public static String getBeanName(Class<?> clazz) {
        //如果有容器注解那么取第一个注解的名称
        Annotation annotation = AnnotationUtil.getIncludeAnnotationFirst(AppContext.CONTAINER_ANNOTATION, clazz.getAnnotations());
        if (annotation != null) {
            String value = AnnotationUtil.getAnnotationPropertyValue(annotation, "value");
            if (StringUtil.isNotEmpty(value)) {
                return value;
            }
        }

        //1.先按照逗号分割
        String name = clazz.getName();
        String[] names = name.split("\\.");
        //反转
        ArrayUtil.reverse(names);
        //首字母小写
        String lowerCaseFirstChar = StringUtil.toLowerCaseFirstChar(names[0]);
        names[0] = lowerCaseFirstChar;
        //拼接
        StringJoiner joiner = new StringJoiner(".");
        for (String s : names) {
            joiner.add(s);
        }
        return joiner.toString();
    }

    //根据名称获取容器
    public static <T> T getBean(String beanName, Class<T> clazz) {
        if (StringUtil.isEmpty(beanName) || clazz == null) {
            return null;
        }
        return (T) AppContext.containerNameAll.get(beanName);
    }

    //根据类获取容器
    public static <T> T getBean(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }
        //如果是接口
        if (clazz.isInterface()) {
            Map<Class<?>, Object> objectsMap = AppContext.containerInterfaceAll.get(clazz);
            if (objectsMap != null) {
                //如果大于1个,那么就报错
                if (objectsMap.size() > 1) {
                    throw new BeanContainerException("接口" + clazz.getName() + "有多个实现类,请指定beanName");
                }
                //如果是接口,那么就返回第一个
                return (T) objectsMap.values().iterator().next();
            }
        }
        //从类中获取
        return (T) AppContext.containerClassAll.get(clazz);
    }

    //根据类型获取多个Bean  , 这种情况一般是继承的关系,接口
    public static <T> List<T> getBeanList(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }
        //如果是接口
        if (clazz.isInterface()) {
            Map<Class<?>, Object> objectsMap = AppContext.containerInterfaceAll.get(clazz);
            if (objectsMap != null) {
                return (List<T>) Collections.singletonList(objectsMap.values());
            }
        }
        //先从类的继承容器中获取
        Map<Class<?>, Object> classObjectMap = AppContext.containerClassExtendAll.get(clazz);
        if (classObjectMap == null) {
            String beanName = getBeanName(clazz);
            Object o = AppContext.containerNameAll.get(beanName);
            if (o != null) {
                return (List<T>) Collections.singletonList(o);
            }
        } else {
            return (List<T>) Collections.singletonList(classObjectMap.values());
        }
        return null;
    }


    //这个只是把对象放入到容器中,不做任何处理(内部字段不会自动注入)
    public static void addAppContainer(Class<?> zClass, Object newInstance) {
        String beanName = getBeanName(zClass);
        addAppContainer(beanName, newInstance);
    }

    public static void addAppContainer(String beanName, Object newInstance) {
        Class<?> clazz = ByteBuddyProxy.getRealClass(newInstance.getClass());
        //放入容器
        AppContext.containerNameAll.put(beanName, newInstance);
        AppContext.containerClassAll.put(clazz, newInstance);
        //如果继承的有接口那么和接口绑定
        Class<?>[] interfaces = clazz.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            //如果是接口,那么就放入到接口的容器中
            Map<Class<?>, Object> objects = AppContext.containerInterfaceAll.computeIfAbsent(anInterface, k -> new ConcurrentHashMap<>());
            objects.put(clazz, newInstance);
        }
        //如果有继承的类
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null && superclass != Object.class) {
            //如果是类,那么就放入到类的容器中
            Map<Class<?>, Object> objects = AppContext.containerClassExtendAll.computeIfAbsent(superclass, k -> new ConcurrentHashMap<>());
            objects.put(clazz, newInstance);
        }
    }





    //指定对象内部字段自动从容器中找找需要的依赖然后注入
    public static void fieldInject(Field declaredField, Object dep) {
        Object target;
        Class<?> type = declaredField.getType();
        if (Collection.class.isAssignableFrom(type)) {
            target = collectionBeanInjection(declaredField);
        } else if (type.isArray()) {
            target = arrayBeanInjection(declaredField);
        } else if (Map.class.isAssignableFrom(type)) {
            target = mapBeanInjection(declaredField);
        } else if (type.isInterface()) {
            target = interfaceBeanInjection(declaredField);
        } else {
            target = AppContext.containerClassAll.get(type);
        }
        if (target == null) {
            Class<?> declaringClass = declaredField.getDeclaringClass();
            log.error("{}类的成员变量:{}没有找到需要注入的对象,类型:{}", declaringClass.getName(), declaredField.getName(), declaredField.getType().getName());
            System.exit(1);
        }
        FieldUtil.setFieldValue(dep, declaredField, target);
    }


    //排序
    public static void orderSort(List<? extends Order> orders) {
        orders.sort((o1, o2) -> {
            if (o1.order() > o2.order()) {
                return 1;
            } else if (o1.order() < o2.order()) {
                return -1;
            }
            return 0;
        });
    }


    private static Object interfaceBeanInjection(Field declaredField) {
        Class<?> declaringClass = declaredField.getDeclaringClass();
        Map<Class<?>, Object> classObjectMap = AppContext.containerInterfaceAll.get(declaredField.getType());
        if (classObjectMap == null) {
            log.error("{}类的成员变量:{},没有找到需要注入的对象,类型:{}", declaringClass.getName(), declaredField.getName(), declaredField.getType().getName());
            System.exit(1);
        }
        //如果接口下有多个实现类,那么报错
        if (classObjectMap.size() > 1) {
            //获取注解AssignBean
            AssignBean fieldAnnotation = AnnotationUtil.getFieldAnnotation(declaredField, AssignBean.class);
            if (fieldAnnotation != null && StringUtil.isNotEmpty(fieldAnnotation.value())) {
                String beanName = fieldAnnotation.value();
                return AppContext.containerNameAll.get(beanName);
            } else {
                log.error("{}类的成员变量:{}的类型接口:{}有多个实现类,请指定@AssignBean", declaringClass.getName(), declaredField.getName(), declaringClass.getName());
                System.exit(1);
            }
        }
        //如果只有一个实现类,那么就获取第一个
        return classObjectMap.values().iterator().next();
    }

    private static Object mapBeanInjection(Field declaredField) {
        Class<?> declaringClass = declaredField.getDeclaringClass();
        Object target;
        Class<?> mapGenericType1 = GenericUtil.getFieldGenericType(declaredField, 0);
        //key只支持String和Class
        if (mapGenericType1 != String.class && mapGenericType1 != Class.class) {
            log.error("{}类的成员变量:{},请指定Map<?,?> key的泛型类型(String | Class)", declaringClass.getName(), declaredField.getName());
            System.exit(1);
        }
        Class<?> mapGenericType2 = GenericUtil.getFieldGenericType(declaredField, 1);
        //如果是空或者Object类型,那么就不处理异常
        if (mapGenericType2 == null || mapGenericType2 == Object.class) {
            log.error("{}类的成员变量:{},请指定Map<?,?> value泛型类型(不能是Object)", declaringClass.getName(), declaredField.getName());
            System.exit(1);
        }
        List<?> beanList = AppContextUtil.getBeanList(mapGenericType2);
        if (beanList == null) {
            log.error("{}类的成员变量:{},没有找到需要注入的对象,类型:{}", declaringClass.getName(), declaredField.getName(), mapGenericType2.getName());
            System.exit(1);
        }
        //如果是字符串,就需要获取类型的实际Bean名称
        if (mapGenericType1 == String.class) {
            Map<String, Object> beanMap = new HashMap<>();
            for (Object bean : beanList) {
                String beanName = AppContextUtil.getBeanName(bean.getClass());
                if (StringUtil.isNotEmpty(beanName)) {
                    beanMap.put(beanName, bean);
                }
            }
            target = beanMap;
        } else {
            Map<Class<?>, Object> beanMap = new HashMap<>();
            for (Object bean : beanList) {
                beanMap.put(bean.getClass(), bean);
            }
            target = beanMap;
        }
        return target;
    }

    private static Object arrayBeanInjection(Field declaredField) {
        Class<?> declaringClass = declaredField.getDeclaringClass();
        Class<?> studentNamesType = declaredField.getType();
        //获取数组的类型
        Class<?> arrayType = studentNamesType.getComponentType();
        //如果是空或者Object类型,那么就不处理异常
        if (arrayType == null || arrayType == Object.class) {
            log.error("{}类的成员变量:{},请指定<?>泛型类型", declaringClass.getName(), declaredField.getName());
            System.exit(1);
        }
        List<?> beanList = AppContextUtil.getBeanList(arrayType);
        if (beanList == null) {
            log.error("{}类的成员变量:{},没有找到需要注入的对象,类型:{}", declaringClass.getName(), declaredField.getName(), declaredField.getType().getName());
            System.exit(1);
        }
        return beanList.toArray();
    }

    private static Object collectionBeanInjection(Field declaredField) {
        Class<?> declaringClass = declaredField.getDeclaringClass();
        Class<?> ListGenericType = GenericUtil.getFieldGenericType(declaredField, 0);
        //如果是空或者Object类型,那么就不处理异常
        if (ListGenericType == null || ListGenericType == Object.class) {
            log.error("{}类的成员变量:{},请指定<?>泛型类型", declaringClass.getName(), declaredField.getName());
            System.exit(1);
        }
        List<?> beanList = AppContextUtil.getBeanList(ListGenericType);
        if (beanList == null) {
            log.error("{}类的成员变量:{},没有找到需要注入的对象,类型:{}", declaringClass.getName(), declaredField.getName(), declaringClass.getName());
            System.exit(1);
        }
        return beanList;
    }


}
